/* This file is part of SpaceSim.
 
 SpaceSim is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 SpaceSim is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with SpaceSim.  If not, see <http://www.gnu.org/licenses/>. */

#include <cmath>

#include "time.h"

#ifndef ENTITY_H
#define ENTITY_H

#define PI 3.14159265358

// entities are objects that have a position and speed

class Entity {
protected:
	float XPos;
	float YPos;
	float XSpeed;
	float YSpeed;
public:
	void SetPos(float _x, float _y) {
		XPos = _x;
		YPos = _y;
	}
	void SetSpeed(float _xs, float _ys) {
		XSpeed = _xs;
		YSpeed = _ys;
	}
	float GetX() {
		return XPos;
	}
	float GetY() {
		return YPos;
	}
};

class RotatableEntity : public Entity {
protected:
	float Rotation;
	float RSpeed;
	float TSpeed;
public:
	void RTToXY() {
		XSpeed += sin(Rotation * PI / 180) * TSpeed;
		YSpeed += cos(Rotation * PI / 180) * TSpeed;
		TSpeed = 0;
	}
};


class OrbitEntity : public Entity {
protected:
	float ORadius;
	float OPeriod;
	float OStart;
public:
	void RecalculateOrbit(float Mass) {	// calculate OPeriod
		float RealRadius = ORadius * 1e8;
		if (Mass == 0.f) {
			OPeriod = (2 * PI * sqrt((RealRadius * RealRadius * RealRadius) / 1.327e20)) / (24 * 60 * 60);
		} else {
			OPeriod = (2 * PI * sqrt((RealRadius * RealRadius * RealRadius) / (Mass * 6.67e-11))) / (24 * 60 * 60);
		}
	}
	
	void RecalculateOrbit() {	// calculate OPeriod
		float RealRadius = ORadius * 1e8;
		OPeriod = (2 * PI * sqrt((RealRadius * RealRadius * RealRadius) / 1.327e20)) / (24 * 60 * 60);
	}
	
	float GetOrbitFraction () {
		float Day = OStart - Time::GetDay();	// Get the part of the orbit we want to show
		return (Day/OPeriod) - (int)(Day/OPeriod);	// return modulo 1
	}
	
	void ROtoXY() {
		float Day = OStart - Time::GetDay();	// Get the part of the orbit we want to show
		float OrbitFraction = Day/OPeriod;
		float OrbitAngle = (OrbitFraction - (int)OrbitFraction)* 2.0 * PI;	// The angle in radians from the top of the orbit
		XPos = sin(OrbitAngle)*ORadius;			// The location is basically a right-angled triangle with hypotenuse Radius, angle Angle and sides X and Y
		YPos = cos(OrbitAngle)*ORadius;
	}
};

class Orbit {
protected:
	float OXPos;
	float OYPos;
	float ORadius;
	float OPeriod;
	float OStart;
public:
	void RecalculateOrbit(float Mass) {	// calculate OPeriod
		float RealRadius = ORadius * 1e8;
		if (Mass == 0.f) {
			OPeriod = (2 * PI * sqrt((RealRadius * RealRadius * RealRadius) / 1.327e20)) / (24 * 60 * 60);
		} else {
			OPeriod = (2 * PI * sqrt((RealRadius * RealRadius * RealRadius) / (Mass * 6.67e-11))) / (24 * 60 * 60);
		}
	}
	
	void RecalculateOrbit() {	// calculate OPeriod and OStart
		float RealRadius = ORadius * 1e8;
		OPeriod = (2 * PI * sqrt((RealRadius * RealRadius * RealRadius) / 1.327e20)) / (24 * 60 * 60);
		// we calculate the ship's angle, and work out the day it was 0
		float OAngle = atan2(-OXPos, OYPos);
		float OFraction = OAngle / 2.0 / PI;
		OStart = Time::GetDay() - OFraction * OPeriod;
	}
	
	void RecalculateOrbitFraction(float Fraction) {	// calculate OPeriod and OStart
		float RealRadius = ORadius * 1e8;
		OPeriod = (2 * PI * sqrt((RealRadius * RealRadius * RealRadius) / 1.327e20)) / (24 * 60 * 60);
		// we calculate the ship's angle, and work out the day it was 0
		OStart = Time::GetDay() - Fraction * OPeriod;
	}
	
	float GetOrbitFraction () {
		float Day = OStart - Time::GetDay();	// Get the part of the orbit we want to show
		return (Day/OPeriod) - (int)(Day/OPeriod) ;
	}
	
	void ROtoXY() {
		float Day = OStart - Time::GetDay();	// Get the part of the orbit we want to show
		float OrbitFraction = Day/OPeriod;
		float OrbitAngle = (OrbitFraction - (int)OrbitFraction)* 2.0 * PI;	// The angle in radians from the top of the orbit
		OXPos = sin(OrbitAngle)*ORadius;			// The location is basically a right-angled triangle with hypotenuse Radius, angle Angle and sides X and Y
		OYPos = cos(OrbitAngle)*ORadius;
	}
	
	float GetOrbitRadius() {
		return ORadius;
	}
};

#endif